#define _POSIX_C_SOURCE 200809L
#include "scanner.h"
#include "threadpool.h"
#include "database.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <unistd.h>

int64_t parse_size(const char *size_str) {
    char *endptr;
    double size = strtod(size_str, &endptr);

    if (endptr == size_str) {
        return -1;
    }

    if (*endptr != '\0') {
        switch (tolower(*endptr)) {
            case 'k': size *= 1024; break;
            case 'm': size *= 1024 * 1024; break;
            case 'g': size *= 1024 * 1024 * 1024; break;
            default: return -1;
        }
    }

    return (int64_t)size;
}

int count_files_recursive(const char *directory, int64_t min_size) {
    int count = 0;
    DIR *dir = opendir(directory);
    if (!dir) {
        fprintf(stderr, "错误: 无法打开目录 %s: %s\n", directory, strerror(errno));
        return 0;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        // 检查是否收到中断信号
        if (g_shutdown_requested) {
            closedir(dir);
            return count;
        }
        
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char full_path[MAX_PATH_LEN];
        int len = snprintf(full_path, MAX_PATH_LEN, "%s/%s", directory, entry->d_name);
        if (len >= MAX_PATH_LEN) {
            fprintf(stderr, "警告: 路径过长，跳过 %s/%s\n", directory, entry->d_name);
            continue;
        }

        struct stat st;
        if (lstat(full_path, &st) == 0) {
            // 跳过符号链接以避免循环
            if (S_ISLNK(st.st_mode)) {
                continue;
            }
            
            if (S_ISDIR(st.st_mode)) {
                // 递归处理子目录
                count += count_files_recursive(full_path, min_size);
            } else if (S_ISREG(st.st_mode) && st.st_size >= min_size) {
                count++;
            }
        } else {
            fprintf(stderr, "警告: 无法访问文件 %s: %s\n", full_path, strerror(errno));
        }
    }

    if (closedir(dir) != 0) {
        fprintf(stderr, "警告: 关闭目录失败 %s: %s\n", directory, strerror(errno));
    }
    return count;
}

static void collect_and_submit_files(const char *directory, int64_t min_size, 
                                     ThreadPool *pool, ScannerContext *context) {
    DIR *dir = opendir(directory);
    if (!dir) {
        fprintf(stderr, "错误: 无法打开目录 %s: %s\n", directory, strerror(errno));
        return;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        // 检查是否收到中断信号
        if (g_shutdown_requested || context->shutdown) {
            closedir(dir);
            return;
        }
        
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char full_path[MAX_PATH_LEN];
        int len = snprintf(full_path, MAX_PATH_LEN, "%s/%s", directory, entry->d_name);
        if (len >= MAX_PATH_LEN) {
            fprintf(stderr, "警告: 路径过长，跳过 %s/%s\n", directory, entry->d_name);
            continue;
        }

        struct stat st;
        if (lstat(full_path, &st) == 0) {
            // 跳过符号链接
            if (S_ISLNK(st.st_mode)) {
                continue;
            }
            
            if (S_ISDIR(st.st_mode)) {
                // 递归处理子目录
                collect_and_submit_files(full_path, min_size, pool, context);
            } else if (S_ISREG(st.st_mode) && st.st_size >= min_size) {
                // 创建任务并提交
                ThreadTask *task = malloc(sizeof(ThreadTask));
                if (task) {
                    task->context = context;
                    strncpy(task->file_path, full_path, MAX_PATH_LEN - 1);
                    task->file_path[MAX_PATH_LEN - 1] = '\0';
                    task->thread_id = 0;
                    
                    if (threadpool_submit(pool, task) != 0) {
                        fprintf(stderr, "错误: 无法提交任务 %s\n", full_path);
                        free(task);
                    }
                } else {
                    fprintf(stderr, "错误: 无法分配任务内存\n");
                }
            }
        } else {
            fprintf(stderr, "警告: 无法访问文件 %s: %s\n", full_path, strerror(errno));
        }
    }

    if (closedir(dir) != 0) {
        fprintf(stderr, "警告: 关闭目录失败 %s: %s\n", directory, strerror(errno));
    }
}

int scan_directory(const char *directory, int64_t min_size, int thread_count, 
                   int force_rehash, void *db) {
    ScannerContext context = {0};
    
    // 首先统计文件总数
    printf("正在统计目录树中的文件...\n");
    int total_files = count_files_recursive(directory, min_size);
    printf("找到 %d 个符合条件的文件。\n\n", total_files);

    if (total_files == 0) {
        printf("未找到符合条件的文件。\n");
        return 0;
    }

    // 初始化扫描上下文
    context.db = (sqlite3 *)db;
    context.directory = directory;
    context.min_size = min_size;
    context.thread_count = thread_count;
    context.force_rehash = force_rehash;
    context.total_files = total_files;
    context.processed_files = 0;
    context.shutdown = 0;

    // 初始化互斥锁
    if (pthread_mutex_init(&context.progress_mutex, NULL) != 0) {
        fprintf(stderr, "初始化进度互斥锁失败\n");
        return -1;
    }

    if (pthread_mutex_init(&context.db_mutex, NULL) != 0) {
        fprintf(stderr, "初始化数据库互斥锁失败\n");
        pthread_mutex_destroy(&context.progress_mutex);
        return -1;
    }

    printf("扫描目录: %s\n", directory);
    printf("最小文件大小: %" PRId64 " 字节\n", min_size);
    printf("线程数: %d\n", thread_count);
    printf("待处理文件总数: %d\n\n", total_files);

    // 创建线程池
    printf("创建线程池，线程数: %d\n", thread_count);
    ThreadPool *thread_pool = threadpool_create(thread_count, &context);
    if (!thread_pool) {
        fprintf(stderr, "错误: 无法创建线程池\n");
        pthread_mutex_destroy(&context.progress_mutex);
        pthread_mutex_destroy(&context.db_mutex);
        return -1;
    }

    printf("开始处理文件...\n");

    // 收集文件并提交任务
    collect_and_submit_files(directory, min_size, thread_pool, &context);

    // 检查是否收到中断信号
    if (g_shutdown_requested) {
        context.shutdown = 1;
    }

    threadpool_wait(thread_pool, &context);

    // 清理线程池
    if (g_shutdown_requested || context.shutdown) {
        fprintf(stderr, "正在清理线程池...\n");
    }
    threadpool_destroy(thread_pool);

    // 清理互斥锁
    pthread_mutex_destroy(&context.progress_mutex);
    pthread_mutex_destroy(&context.db_mutex);

    if (g_shutdown_requested || context.shutdown) {
        fprintf(stderr, "扫描被中断。已处理 %d 个文件。\n", context.processed_files);
    } else {
        printf("扫描完成。已处理 %d 个文件。\n", context.processed_files);
    }
    return 0;
}
